local Sol = LibStub("Sol")

local MAX_LIST_ITEMS = 20
local MIN_ID = 210001
local MAX_ID = 224717
local lastUpdate = nil

local qualityColorVals = {
    "FFFFFF",
    "FFFFFF",
    "00FF00",
    "0072BC",
    "C805F8",
    "F68E56",
    "A37D50",
    "A864A8",
    "F7941D",
    "FFF466",
    "309166",
    "FFFFFE",
}
local qualityColorNames = {
    "Any quality",
    ITEM_QUALITY0_DESC or "White",
    ITEM_QUALITY1_DESC,
    ITEM_QUALITY2_DESC,
    ITEM_QUALITY3_DESC,
    ITEM_QUALITY4_DESC,
    ITEM_QUALITY5_DESC,
    "Item Mall",
    "Quest",
    "Skill",
    "Passive Skill",
    "All others",
}
local presetNames = {
    "Equipment",
    "Skills",
    "Cards",
    "Recipes",
    "Runes",
    "All (NOT recommended)",
}
local presetValues = {
    { min = 200000, max = 225000 },
    { min = 490000, max = 495000 },
    { min = 770000, max = 771000 },
    { min = 550000, max = 551200 },
    { min = 520021, max = 520830 },
    { min = 0, max = 999999 },
}

local qualityColors = {}
local itemList = {}
itemList.count = 0

function ItemPreview:LoadConfig()
    self.list = ItemPreview_ItemListFrameItemsList
    
    for i = 1, MAX_LIST_ITEMS do 
        local item = _G["ItemPreview_ItemListFrameItemsListItem" .. i]
        item.label = _G["ItemPreview_ItemListFrameItemsListItem" .. i .. "Label"]
    end
    
    local scrollBar = ItemPreview_ItemListFrameItemsListScrollBar
    scrollBar:SetValueStepMode("INT")
    
    for i = 1, #qualityColorVals do
        qualityColors[i] = Sol.color.ColorText(qualityColorNames[i], qualityColorVals[i])
    end
    
    Sol.config.SetupDropdown(ItemPreview_ItemListFrameQualityFilter, qualityColors, 1, 100, self.SelectQuality)
    Sol.config.SetupDropdown(ItemPreview_ItemListFrameType, presetNames, 1, 130, self.SelectType)
    self:InitSlider(ItemPreview_ItemListConfigFrameUpdateSpeed, "Update Speed", 1, 300, "INT", self.settings.UpdateSpeed)
    ItemPreview_ItemListConfigFrameHideInvalid:SetChecked(self.settings.HideInvalid)
    
    ItemPreview_ItemListFrameTitle:SetText("ItemPreview")
    
    self.SelectType(_, 1, _)
    self:UpdateList(self.list)
end

function ItemPreview.SelectQuality(dropdown, id, val)
    ItemPreview:UpdateList(ItemPreview.list)
end

function ItemPreview.SelectType(dropdown, id, val)
    ItemPreview_ItemListConfigFrameStartID:SetNumber(presetValues[id].min)
    ItemPreview_ItemListConfigFrameEndID:SetNumber(presetValues[id].max)
end

function ItemPreview:HideInvalid(hide)
    self.settings.HideInvalid = hide
    self:UpdateList(self.list)
end

function ItemPreview:UpdateList(list)
    if not itemList or not list then return end
    local start = ItemPreview_ItemListConfigFrameStartID:GetNumber()
    local endID = ItemPreview_ItemListConfigFrameEndID:GetNumber()
    
    local scrollBar = _G[list:GetName() .. "ScrollBar"]
    local offset = scrollBar:GetValue()
    if offset < 0 then
        offset = 0
    end
    
    for i = 1, MAX_LIST_ITEMS do
        local button = _G[list:GetName() .. "Item" .. i]
        button:Hide()
    end
    
    local buttonCount = 0  -- which physical button in the list we're on
    local matchCount = 0   -- how many items match search criteria so far
    for i = start, endID do
        local item = itemList[i] and itemList[i].name
        if self:ListShouldShowItem(list, item) then
            itemList[i].show = true
            -- item matches search criteria, but may not be in scroll range
            matchCount = matchCount + 1
            if matchCount > offset and buttonCount < MAX_LIST_ITEMS then 
                -- item is in scroll range
                buttonCount = buttonCount + 1
                local button = _G[list:GetName() .. "Item" .. buttonCount]
                button:Show()
                button.label:SetText(item)
            end
        elseif itemList[i] then
            itemList[i].show = false        
        end
    end
    
    local max = matchCount - MAX_LIST_ITEMS
    if max < 0 then
        max = 0
    end
    scrollBar:SetMaxValue(max)
end

function ItemPreview:ListShouldShowItem(list, item)
    if not item then return false end
    
    local hideInvalid = ItemPreview_ItemListConfigFrameHideInvalid:IsChecked()
    if hideInvalid and item:match("^|Hitem:%x+|h|cff(%x+)%[%]|r|h$") then
        return false
    end        
    
    local searchStr = ItemPreview_ItemListFrameSearchBox:GetText() or ""
    if not item:match(searchStr) then
        return false
    end
    
    local quality = UIDropDownMenu_GetSelectedID(ItemPreview_ItemListFrameQualityFilter)
    local itemColor = item:sub(19, 24)
    if quality == 1 or (qualityColorVals[quality] == itemColor) then
        -- 1 is any; the others are specific colors
        return true
    elseif quality == #qualityColorVals then
        -- the last one is "All others"
        for i = 2, #qualityColorVals - 1 do
            if qualityColorVals[i] == itemColor then
                return false
            end
        end
        return true
    else
        return false
    end
end

function ItemPreview:SelectItem(item, key)
    if item:GetParent().selectedItem then
        item:GetParent().selectedItem:UnlockHighlight()
    end
    item:LockHighlight()
    item:GetParent().selectedItem = item
    ItemPreviewFrame_SetItemLink( ItemPreviewFrame, item.label:GetText() )
end

function ItemPreview:Scroll(list, delta)
    local scrollBar = _G[list:GetName() .. "ScrollBar"]
    local newVal = scrollBar:GetValue() + ((delta > 0 and -1) or 1)
    if newVal >= scrollBar:GetMinValue() and newVal <= scrollBar:GetMaxValue() then
        scrollBar:SetValue(newVal)
    end
end

function ItemPreview:OnScroll(item, delta)
    -- TODO: abstract out so there's not nearly the same code in two places
    
    --self:UpdateList(self.list)
    local list = self.list
    local start = ItemPreview_ItemListConfigFrameStartID:GetNumber()
    local endID = ItemPreview_ItemListConfigFrameEndID:GetNumber()
    
    local scrollBar = _G[list:GetName() .. "ScrollBar"]
    local offset = scrollBar:GetValue()
    if offset < 0 then
        offset = 0
    end
    
    for i = 1, MAX_LIST_ITEMS do
        local button = _G[list:GetName() .. "Item" .. i]
        button:Hide()
    end
    
    local buttonCount = 0  -- which physical button in the list we're on
    local matchCount = 0   -- how many items match search criteria so far
    for i = start, endID do
        local item = itemList[i] and itemList[i].name
        if itemList[i] and itemList[i].show then
            -- item matches search criteria, but may not be in scroll range
            matchCount = matchCount + 1
            if matchCount > offset then 
                -- item is in scroll range
                buttonCount = buttonCount + 1
                local button = _G[list:GetName() .. "Item" .. buttonCount]
                button:Show()
                button.label:SetText(item)
                
                if buttonCount >= MAX_LIST_ITEMS then
                    return 
                end 
            end
        end
    end
end

function ItemPreview:Item_OnEnter(item)
    if item.label:GetText() == "" then return end
    
    GameTooltip:SetOwner(item, "ANCHOR_LEFT")
    GameTooltip:SetHyperLink(item.label:GetText())
    
    local hexID = item.label:GetText():match("^|Hitem:(.-)|h.*")
    if hexID then
        GameTooltip:AddLine(" ")
        GameTooltip:AddLine("Item ID: " .. Sol.math.HexToDec(hexID))
    end
end

function ItemPreview:Search()
    self:UpdateList(self.list)
end

function ItemPreview:RefreshList()
    self.currentID = ItemPreview_ItemListConfigFrameStartID:GetNumber()
    ItemPreview_ItemListConfigFrameStartID:ClearFocus()
    ItemPreview_ItemListConfigFrameEndID:ClearFocus()
    ItemPreview_ItemListFrameSearchBox:ClearFocus()
end

function ItemPreview:OnListUpdate()
    if not self.currentID then return end
    
    local endID = ItemPreview_ItemListConfigFrameEndID:GetNumber()
    local startID = ItemPreview_ItemListConfigFrameStartID:GetNumber()
    local start = self.currentID
    for i = 0, self.settings.UpdateSpeed do
        self.currentID = start + i
        if self.currentID > endID then 
            ItemPreview_ItemListFrameTitle:SetText("ItemPreview")
            itemList.count = self.currentID - startID + 1
            self.currentID = nil
            self:UpdateList(self.list)
            return
        end
        
        if not itemList[self.currentID] then
            local link = self:MakeItemLinkFromID(Sol.math.DecToHex(self.currentID))
            itemList[self.currentID] = { name = link, show = false }
        end
    end
    
    local percent = math.ceil(100 * (self.currentID - startID) / (endID - startID))
    ItemPreview_ItemListFrameTitle:SetText(string.format("ItemPreview (Working: %d%%)", percent))
    itemList.count = self.currentID - ItemPreview_ItemListConfigFrameStartID:GetNumber() + 1
    
    -- give them a little something to tide them over ^^
    if not lastUpdate or GetTime() - lastUpdate > self.settings.UpdateInterval then
        lastUpdate = GetTime()
        self:UpdateList(self.list)
    end
    
    GameTooltip1:Hide()
    GameTooltip2:Hide()
end

function ItemPreview:SearchElement_OnEnter(element, text)
    GameTooltip:SetOwner(element, "ANCHOR_LEFT")
    GameTooltip:SetText(text)
    GameTooltip:Show()
end

-- Slider
function ItemPreview:OnValueChanged(slider)
    local value = Sol.math.Round(slider:GetValue(), 2)
	_G[slider:GetName().."Value"]:SetText(value)
    self.settings.UpdateSpeed = value
end

function ItemPreview:InitSlider(slider, nameText, min, max, stepMode, value)
    local sliderName = slider:GetName()
    slider:SetValueStepMode(stepMode)
    slider:SetMinMaxValues(min, max)
    slider:SetValue(value or min)
	_G[sliderName .. "Name"]:SetText(nameText)
	_G[sliderName .. "Value"]:SetText(value or min)
	_G[sliderName .. "Low"]:SetText(min)
	_G[sliderName .. "High"]:SetText(max)
end

